package com.ruoyi.web.controller.wxpay;

import com.github.binarywang.wxpay.bean.notify.SignatureHeader;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.util.WxPayUtil;
import com.ruoyi.web.service.WxPayService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * 微信支付控制器
 * 
 * @author ruoyi
 */
@Api(tags = "微信支付")
@RestController
@RequestMapping("/wxpay")
public class WxPayController {

    private static final Logger log = LoggerFactory.getLogger(WxPayController.class);

    @Autowired
    private WxPayService wxPayService;

    @Autowired
    private WxPayUtil wxPayUtil;

    /**
     * 创建微信支付订单
     */
    @ApiOperation(value = "创建微信支付订单")
    @PostMapping("/createOrder")
    public AjaxResult createOrder(
            @ApiParam("用户openid") @RequestParam String openid,
            @ApiParam("支付金额（分）") @RequestParam Integer total,
            @ApiParam("商品描述") @RequestParam String description,
            @ApiParam("商户订单号") @RequestParam String outTradeNo) {
        
        try {
            return wxPayService.createOrder(openid, total, description, outTradeNo);
        } catch (Exception e) {
            log.error("创建微信支付订单失败", e);
            return AjaxResult.error("创建支付订单失败");
        }
    }

    /**
     * 创建微信支付订单（金额以元为单位）
     */
    @ApiOperation(value = "创建微信支付订单（金额以元为单位）")
    @PostMapping("/createOrderByYuan")
    public AjaxResult createOrderByYuan(
            @ApiParam("用户openid") @RequestParam String openid,
            @ApiParam("支付金额（元）") @RequestParam Double totalYuan,
            @ApiParam("商品描述") @RequestParam String description,
            @ApiParam("商户订单号（可选，不传则自动生成）") @RequestParam(required = false) String outTradeNo) {
        
        try {
            // 元转分
            Integer total = wxPayService.yuanToFen(totalYuan);
            // 如果没有传订单号，则自动生成
            if (outTradeNo == null || outTradeNo.trim().isEmpty()) {
                outTradeNo = wxPayService.generateOutTradeNo();
            }
            return wxPayService.createOrder(openid, total, description, outTradeNo);
        } catch (Exception e) {
            log.error("创建微信支付订单失败", e);
            return AjaxResult.error("创建支付订单失败");
        }
    }

    /**
     * 微信支付退款
     */
    @ApiOperation(value = "微信支付退款")
    @PostMapping("/refund")
    public AjaxResult refund(
            @ApiParam("商户订单号") @RequestParam String outTradeNo,
            @ApiParam("商户退款单号") @RequestParam String outRefundNo,
            @ApiParam("退款金额（分）") @RequestParam Integer refundAmount,
            @ApiParam("原订单金额（分）") @RequestParam Integer totalAmount,
            @ApiParam("退款原因") @RequestParam(defaultValue = "用户申请退款") String reason) {
        
        try {
            return wxPayService.refund(outTradeNo, outRefundNo, refundAmount, totalAmount, reason);
        } catch (Exception e) {
            log.error("微信支付退款失败", e);
            return AjaxResult.error("退款失败");
        }
    }

    /**
     * 微信支付退款（金额以元为单位）
     */
    @ApiOperation(value = "微信支付退款（金额以元为单位）")
    @PostMapping("/refundByYuan")
    public AjaxResult refundByYuan(
            @ApiParam("商户订单号") @RequestParam String outTradeNo,
            @ApiParam("商户退款单号（可选，不传则自动生成）") @RequestParam(required = false) String outRefundNo,
            @ApiParam("退款金额（元）") @RequestParam Double refundAmountYuan,
            @ApiParam("原订单金额（元）") @RequestParam Double totalAmountYuan,
            @ApiParam("退款原因") @RequestParam(defaultValue = "用户申请退款") String reason) {
        
        try {
            // 元转分
            Integer refundAmount = wxPayService.yuanToFen(refundAmountYuan);
            Integer totalAmount = wxPayService.yuanToFen(totalAmountYuan);
            // 如果没有传退款单号，则自动生成
            if (outRefundNo == null || outRefundNo.trim().isEmpty()) {
                outRefundNo = wxPayService.generateOutRefundNo();
            }
            return wxPayService.refund(outTradeNo, outRefundNo, refundAmount, totalAmount, reason);
        } catch (Exception e) {
            log.error("微信支付退款失败", e);
            return AjaxResult.error("退款失败");
        }
    }

    /**
     * 微信支付回调接口
     */
    @ApiOperation(value = "微信支付回调")
    @PostMapping("/notify")
    public String notify(HttpServletRequest request) {
        log.info("微信支付回调接口被调用");
        
        try {
            com.github.binarywang.wxpay.service.WxPayService payService = wxPayUtil.getWxPayService();
            
            // 构建签名头
            SignatureHeader header = new SignatureHeader();
            header.setTimeStamp(request.getHeader("Wechatpay-Timestamp"));
            header.setNonce(request.getHeader("Wechatpay-Nonce"));
            header.setSignature(request.getHeader("Wechatpay-Signature"));
            header.setSerial(request.getHeader("Wechatpay-Serial"));
            
            // 获取请求体
            String requestBody = getRequestBody(request.getInputStream());
            log.info("微信支付回调请求体: {}", requestBody);
            
            // 解析回调结果
            Object notifyResult = payService.parseOrderNotifyV3Result(requestBody, header);
            log.info("微信支付回调解析结果: {}", notifyResult);
            
            // 这里可以添加业务逻辑，比如更新订单状态等
            // TODO: 根据实际业务需求处理支付成功后的逻辑
            
            // 返回成功响应给微信
            return "{\"code\": \"SUCCESS\", \"message\": \"成功\"}";
            
        } catch (Exception e) {
            log.error("处理微信支付回调失败", e);
            // 返回失败响应给微信
            return "{\"code\": \"FAIL\", \"message\": \"失败\"}";
        }
    }

    /**
     * 查询订单状态
     */
    @ApiOperation(value = "查询订单状态")
    @GetMapping("/queryOrder")
    public AjaxResult queryOrder(@ApiParam("商户订单号") @RequestParam String outTradeNo) {
        try {
            com.github.binarywang.wxpay.service.WxPayService payService = wxPayUtil.getWxPayService();
            
            // 查询订单
            Object queryResult = payService.queryOrderV3(null, outTradeNo);
            
            Map<String, Object> result = new HashMap<>();
            result.put("data", queryResult);
            
            return AjaxResult.success(result);
            
        } catch (WxPayException e) {
            log.error("查询订单状态失败", e);
            return AjaxResult.error("查询订单状态失败: " + e.getMessage());
        }
    }

    /**
     * 关闭订单
     */
    @ApiOperation(value = "关闭订单")
    @PostMapping("/closeOrder")
    public AjaxResult closeOrder(@ApiParam("商户订单号") @RequestParam String outTradeNo) {
        try {
            com.github.binarywang.wxpay.service.WxPayService payService = wxPayUtil.getWxPayService();
            
            // 关闭订单
            payService.closeOrderV3(outTradeNo);
            
            return AjaxResult.success("订单关闭成功");
            
        } catch (WxPayException e) {
            log.error("关闭订单失败", e);
            return AjaxResult.error("关闭订单失败: " + e.getMessage());
        }
    }

    /**
     * 读取请求体内容
     */
    private String getRequestBody(InputStream inputStream) throws IOException {
        StringBuilder sb = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        }
        return sb.toString();
    }

    /**
     * 生成商户订单号
     */
    @ApiOperation(value = "生成商户订单号")
    @GetMapping("/generateOutTradeNo")
    public AjaxResult generateOutTradeNo() {
        try {
            String outTradeNo = wxPayService.generateOutTradeNo();
            Map<String, Object> result = new HashMap<>();
            result.put("outTradeNo", outTradeNo);
            return AjaxResult.success(result);
        } catch (Exception e) {
            log.error("生成商户订单号失败", e);
            return AjaxResult.error("生成商户订单号失败");
        }
    }

    /**
     * 生成商户退款单号
     */
    @ApiOperation(value = "生成商户退款单号")
    @GetMapping("/generateOutRefundNo")
    public AjaxResult generateOutRefundNo() {
        try {
            String outRefundNo = wxPayService.generateOutRefundNo();
            Map<String, Object> result = new HashMap<>();
            result.put("outRefundNo", outRefundNo);
            return AjaxResult.success(result);
        } catch (Exception e) {
            log.error("生成商户退款单号失败", e);
            return AjaxResult.error("生成商户退款单号失败");
        }
    }

    /**
     * 金额转换：元转分
     */
    @ApiOperation(value = "金额转换：元转分")
    @GetMapping("/yuanToFen")
    public AjaxResult yuanToFen(@ApiParam("金额（元）") @RequestParam Double yuan) {
        try {
            Integer fen = wxPayService.yuanToFen(yuan);
            Map<String, Object> result = new HashMap<>();
            result.put("yuan", yuan);
            result.put("fen", fen);
            return AjaxResult.success(result);
        } catch (Exception e) {
            log.error("金额转换失败", e);
            return AjaxResult.error("金额转换失败");
        }
    }

    /**
     * 金额转换：分转元
     */
    @ApiOperation(value = "金额转换：分转元")
    @GetMapping("/fenToYuan")
    public AjaxResult fenToYuan(@ApiParam("金额（分）") @RequestParam Integer fen) {
        try {
            Double yuan = wxPayService.fenToYuan(fen);
            Map<String, Object> result = new HashMap<>();
            result.put("fen", fen);
            result.put("yuan", yuan);
            return AjaxResult.success(result);
        } catch (Exception e) {
            log.error("金额转换失败", e);
            return AjaxResult.error("金额转换失败");
        }
    }
}
